module sw.contentmode;
import nazo.http, nazo.xhtml, std.uri, nazo.string, std.date, nazo.file;
import sw.mode, sw.siteconfig, sw.client, sw.page, sw.utils;
version(Wiki){
  import sw.wiki.article;
}

///ソースを表示するモード
class SourceMode:Mode!(){
  private string filename;
  ///コンストラクタ
  this(SiteConfig* cfg, string filename){
    super(cfg);
    this.filename=filename;
  }
  override final void response(){
    if(!exists(filename)){HttpResponse.write("");return;}
    HttpResponse.write(cast(string)read(filename),200,["Last-Modified":std.date.toUTCString(getLastWriteTime(filename)),
      "Content-Disposition": "inline; filename=\"" ~ encodeComponent(filename) ~ "\"",
      "Content-Type": "text/plain; charset=utf-8"]);
  }
}

///内容があるモード
class ContentMode(ModeMethod m = ModeMethod.GET):Mode!(m){
  this(SiteConfig* cfg){
    super(cfg);
  }
  abstract string filename();
  protected string[string] headers;
  abstract string contentType();
  protected d_time lastModified(){
    return 0;
  }
  d_time modified;
  override final void response(){
    if(Client.authority!=Client.Authority.Admin&&cfg.useLastModified){
      modified=this.lastModified;
      if(modified!=0)
         headers["Last-Modified"]=std.date.toUTCString(modified);
    }
    headers["Content-Type"]=contentType() ~ "; charset=utf-8";

    headers["Content-Disposition"]="inline; filename=\"" ~ encodeComponent(filename()) ~ "\"";
    
//    try{
      HttpResponse.write(content(),200,headers);
//    }catch(AcceptException e){
//      HttpResponse.write("そのAcceptには対応してませんよん",406);
//    }
  }
  protected abstract string content();
}

///XMLの基礎モード
class XmlMode(ModeMethod m = ModeMethod.GET):ContentMode!(m){
  this(SiteConfig* cfg){
    super(cfg);
  }
  override string contentType(){
    return "application/xml";
  }
}

template Page(){
  private string _title;
  static if(is(typeof(super.title))){
    override final string title(){
      return _title~status;
    }
  }
  string status(){return "";};
  this(SiteConfig* cfg){
    super(cfg);
    _title=getPageTitle(cfg);
    page = new Article;
    *page=Article(_title);
  }
  final bool isPage(){return true;};
}

///ページに関するモード(タイトル取得の為だけに派生…)
class XhtmlPageMode(ModeMethod m = ModeMethod.GET):XhtmlMode!(m){
  mixin Page;
}

class NotValidQueryException:Exception{
  this(){
    super("NotValidQueryException: ");
  }
}

///XHTMLの基礎モード
///contentBodyを呼び出してからtitleやpageを呼び出し最後にWikiを生成します。
class XhtmlMode(ModeMethod m = ModeMethod.GET):XmlMode!(m){
  this(SiteConfig* cfg){
    super(cfg);
  }
  override string filename(){
    return title() ~ ".xml";
  }
  abstract string title();
  version(Wiki){
    protected Article* page;
  }else{
    protected void* page;
  }
  string[] scripts;
  bool useJSCookie = false;
  string footer;
  override final string contentType(){
    string rv;
    if(Http.useragent.find("MSIE"))//IEの場合。FIXME: safariにも引っかかってしまうかも? あとWebサービスにも。
      return "application/xml";
    static string[] acceptList=["application/xhtml+xml", "application/xml", "text/xml", "application/*", "*/*"];
    rv = Http.allowAccept(acceptList);
    if(rv=="application/*")
      return "application/xhtml+xml";
    if(rv=="*/*")
      if(Client.authority==Client.Authority.Bot)
        return "text/html";
      else
        return "application/xhtml+xml";
    if(rv=="")
      return "text/html";

    return rv;
  }
  override final string content(){
    auto content=contentBody();
    scope xhtml=new sw.page.Page!(XhtmlVersion.XHTML_PLUS_RDFA)(cfg,content~footer,title,page,scripts,this.modified);
    xhtml.useJSCookie = useJSCookie;
    return xhtml.getContent();
  }
  protected abstract string contentBody();
}
